// Copyright 2025 CCC
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* eslint-disable @typescript-eslint/no-unused-expressions */
import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios';
import axios from 'axios';

import { RequestOptions, CreateAxiosOptions, Result } from './types';
import { AxiosCanceler } from './axiosCancel';

import { deepClone } from '@/utils';
import { isFunction } from '@/utils/is';
/**
 * @description axios模块
 */
export class VAxios {
  /**
   * Axios 类用于封装 Axios 实例的创建和配置。
   */
  private axiosInstance: AxiosInstance;
  private options: CreateAxiosOptions;
  constructor(options: CreateAxiosOptions) {
    this.options = options;

    this.axiosInstance = axios.create(options);
    this.setupInterceptors();
  }
  /**
   * 创建axios实例
   */
  private createAxios(config: CreateAxiosOptions): void {
    this.axiosInstance = axios.create(config);
  }
  private getTransform() {
    const { transform } = this.options;

    return transform;
  }
  getAXIOS(): AxiosInstance {
    return this.axiosInstance;
  }
  /**@descriptions 重新配置axios */
  configAxios(config: CreateAxiosOptions) {
    if (!this.axiosInstance) {
      return;
    }

    this.createAxios(config);
  }
  /**@description 设置通用header */
  setHeader(headers: any): void {
    if (!this.axiosInstance) {
      return;
    }

    Object.assign(this.axiosInstance.defaults.headers, headers);
  }
  /**@description 拦截器配置 */
  private setupInterceptors() {
    const transform = this.getTransform();

    if (!transform) {
      return;
    }

    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform;
    const axiosCanceler = new AxiosCanceler();
    // 请求拦截器配置处理
    this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig<any>) => {
      const { headers: { ignoreCancelToken } = { ignoreCancelToken: false } } = config;
      !ignoreCancelToken && axiosCanceler.addPending(config);

      if (requestInterceptors && isFunction(requestInterceptors)) {
        config = requestInterceptors(config) as InternalAxiosRequestConfig<any>;
      }

      return config;
    }, undefined);
    //请求拦截器错误捕获
    requestInterceptorsCatch &&
      isFunction(requestInterceptorsCatch) &&
      this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);

    //响应结果拦截器处理
    this.axiosInstance.interceptors.response.use((res: AxiosResponse<any, any>) => {
      res && axiosCanceler.removePending(res.config);

      if (responseInterceptors && isFunction(responseInterceptors)) {
        res = responseInterceptors(res) as AxiosResponse<any, any>;
      }

      return res;
    }, undefined);

    //响应结果拦截器错误捕获
    responseInterceptorsCatch &&
      isFunction(responseInterceptorsCatch) &&
      this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
  }
  /**
   *请求方法
   * @param config
   * @param options
   * @returns
   */
  request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
    let conf: AxiosRequestConfig = deepClone(config);
    const transform = this.getTransform();

    const { requestOptions } = this.options;

    const opt: RequestOptions = Object.assign({}, requestOptions, options);

    const { beforeRequestHook, requestCatch, transformRequestData } = transform || {};

    if (beforeRequestHook && isFunction(beforeRequestHook)) {
      conf = beforeRequestHook(conf, opt);
    }

    return new Promise((resolve, reject) => {
      this.axiosInstance
        .request<any, AxiosResponse<Result>>(conf)
        .then((res: AxiosResponse<Result>) => {
          // 请求是否被取消
          const isCancel = axios.isCancel(res);

          if (
            transformRequestData &&
            isFunction(transformRequestData) &&
            !isCancel &&
            !conf.responseType
          ) {
            const ret = transformRequestData(res, opt);

            // ret !== undefined ? resolve(ret) : reject(new Error('request error!'));
            return resolve(ret);
          }

          resolve(res?.data as unknown as Promise<T>);

          reject(res as unknown as Promise<T>);
        })
        .catch((e: Error) => {
          if (requestCatch && isFunction(requestCatch)) {
            reject(requestCatch(e));

            return;
          }

          reject(e);
        });
    });
  }
}
